home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / util / pop2d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-29  |  12.0 KB  |  531 lines

  1. /* pop2d - Post Office Protocol server */
  2.  
  3. static char  rcsid[] = "@(#) $Header: pop2d.c,v 1.4 91/07/08 13:04:15 deyke Exp $";
  4.  
  5. /*
  6.  
  7.    This server implements the POP2 protocol described in RFC937.
  8.    It should work with any system derived from Unix 4.2/4.3 BSD.
  9.    It adds a small feature to the standard protocol:
  10.  
  11.    The non-standard command "save" is supported. If a "save"
  12.    command is issued, any message deleted from the user's mail
  13.    spool file is saved in the "save" file (by default this is
  14.    named by appending ".bak" to the spool file).
  15.  
  16.    To install this do the following:
  17.  
  18.    1) Add a line to inetd.conf, as follows:
  19.  
  20.       pop2 stream tcp nowait root /etc/pop2d pop2d
  21.  
  22.    2) Add a line to /etc/services, as follows
  23.  
  24.       pop2 109/tcp
  25.  
  26.       Dont forget to remake maps if YP is running
  27.  
  28. */
  29.  
  30. #define _HPUX_SOURCE
  31.  
  32. #include <sys/types.h>
  33.  
  34. #include <stdio.h>
  35.  
  36. #include <ctype.h>
  37. #include <fcntl.h>
  38. #include <pwd.h>
  39. #include <signal.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <sys/stat.h>
  43. #include <unistd.h>
  44.  
  45. extern char  *crypt();
  46. extern char  *mktemp();
  47. extern struct passwd *getpwnam();
  48.  
  49. #ifdef __STDC__
  50. #define __ARGS(x)       x
  51. #else
  52. #define __ARGS(x)       ()
  53. #endif
  54.  
  55. #define null    0
  56. #define helo    1
  57. #define fold    2
  58. #define raed    3
  59. #define retr    4
  60. #define acks    5
  61. #define ackd    6
  62. #define nack    7
  63. #define quit    8
  64. #define save    9
  65. #define NKEYS   9
  66.  
  67. static struct key_word {
  68.   char  *key;
  69.   int  val;
  70.   int  args;
  71. } keytab[] = {
  72.   "null", null, 0,
  73.   "helo", helo, 2,
  74.   "fold", fold, 1,
  75.   "read", raed, 1,
  76.   "retr", retr, 0,
  77.   "acks", acks, 0,
  78.   "ackd", ackd, 0,
  79.   "nack", nack, 0,
  80.   "quit", quit, 0,
  81.   "save", save, 1       /* Non standard */
  82. };
  83.  
  84. #define AUTH    0
  85. #define MBOX    1
  86. #define ITEM    2
  87. #define NEXT    3
  88. #define DONE    4
  89. #define ERRO    5
  90.  
  91. static int state_tab[4][NKEYS] = {
  92.  
  93. /*           helo  fold  read  retr  acks  ackd  nack  quit  save  */
  94. /*-----------------------------------------------------------------*/
  95. /* AUTH: */  MBOX, ERRO, ERRO, ERRO, ERRO, ERRO, ERRO, DONE, ERRO,
  96. /* MBOX: */  ERRO, MBOX, ITEM, ERRO, ERRO, ERRO, ERRO, DONE, MBOX,
  97. /* ITEM: */  ERRO, MBOX, ITEM, NEXT, ERRO, ERRO, ERRO, DONE, MBOX,
  98. /* NEXT: */  ERRO, ERRO, ERRO, ERRO, ITEM, ITEM, ITEM, DONE, ERRO
  99.  
  100. };
  101.  
  102. /*
  103.  
  104.         State Diagram corresponding to the state transition table
  105.         represented by the variable state_tab[][]
  106.  
  107.                  |
  108.                  | helo
  109.                  |
  110.                 \|/
  111.                --------------      quit           -----------
  112.           ------->|     MBOX     |-----------------> |    DONE   |
  113.        fold  |         --------------                     -----------
  114.     or save  |         |   |      /|\                         /|\
  115.           ---------    |       |                           |
  116.                |       |                           |
  117.               read |       | fold or save              |
  118.               \|/      |                           |
  119.                --------------      quit                |
  120.           ------->|     ITEM     |-------------------------
  121.        read  |         --------------                          |
  122.          |         |   |      /|\                          |
  123.           ---------    |       | ack(s/d)                  |
  124.               retr |       |                           |
  125.               \|/      |                           |
  126.                --------------      quit                |
  127.               |     NEXT     |-------------------------
  128.                --------------
  129.  
  130.                          --------------
  131.                         |     ERRO     |
  132.                          --------------
  133.  
  134. */
  135.  
  136. #define MAILDIR         "/usr/mail/"
  137. #define MAXMSGS         1000
  138. #define SAVEFILE        ".bak"
  139.  
  140. struct message {
  141.   long  headp;
  142.   int  deleted;
  143.   int  lines;
  144. };
  145.  
  146. static FILE *fsave;
  147. static FILE *ftemp;
  148. static char  *mdir;
  149. static char  line[1024];
  150. static char  mailbox[1024];
  151. static char  mailtmp[1024];
  152. static char  myargv[4][1024];
  153. static char  tmplate[] = "/tmp/popXXXXX";
  154. static int  cur_msg;
  155. static int  cur_msg_len;
  156. static int  msg_cnt;
  157. static int  myargc;
  158. static int  nlines;
  159. static int  nmsg;
  160. static int  opened;
  161. static struct key_word key;
  162. static struct message msg[MAXMSGS+2];
  163. static struct passwd *pwd;
  164.  
  165. static int parse __ARGS((void));
  166. static int check_user __ARGS((char *user, char *passwd));
  167. static int lexical __ARGS((void));
  168. static int whatkey __ARGS((char *s));
  169. static int openit __ARGS((void));
  170. static void closeit __ARGS((void));
  171. static int msglen __ARGS((int n));
  172. static void outmsg __ARGS((int n));
  173. static int my_gets __ARGS((char *s));
  174. static int openbk __ARGS((char *savefile));
  175. static int flock __ARGS((FILE *fp, int l_type));
  176.  
  177. /*---------------------------------------------------------------------------*/
  178.  
  179. int  main(argc, argv)
  180. int  argc;
  181. char  **argv;
  182. {
  183.   mdir = (argc >= 2) ? argv[1] : MAILDIR;
  184.   gethostname(line, sizeof(line));
  185.   printf("+ POP2 %s\r\n", line);
  186.   while (parse() > 0) ;
  187.   if (*mailtmp) unlink(mailtmp);
  188.   return 0;
  189. }
  190.  
  191. /*---------------------------------------------------------------------------*/
  192.  
  193. /* Main parser - guides us through states and checks protocol compliance */
  194.  
  195. static int  parse()
  196. {
  197.  
  198.   char  savebox[1024];
  199.   int  next_state;
  200.   int  token;
  201.   static int  cur_state;
  202.  
  203.   alarm(6 * 3600);
  204.   token = lexical();
  205.   if (token < 0) return (-1);
  206.   next_state = state_tab[cur_state][token-1];
  207.   switch (next_state) {
  208.   case MBOX:
  209.     switch (token) {
  210.     case helo:
  211.       if (check_user(myargv[1], myargv[2])) {
  212.     printf("- Logon incorrect\r\n");
  213.     return (-1);
  214.       }
  215.       strcpy(mailbox, mdir);
  216.       strcat(mailbox, myargv[1]);
  217.       msg_cnt = openit();
  218.       printf("#%d messages in %s\r\n", msg_cnt, mailbox);
  219.       break;
  220.     case fold:
  221.       strcpy(mailbox, myargv[1]);
  222.       msg_cnt = openit();
  223.       printf("#%d messages in %s\r\n", msg_cnt, mailbox);
  224.       break;
  225.     case save:
  226.       if (myargc >= 1 && strlen(myargv[1]))
  227.     strcpy(savebox, myargv[1]);
  228.       else {
  229.     strcpy(savebox, mailbox);
  230.     strcat(savebox, SAVEFILE);
  231.       }
  232.       if (openbk(savebox))
  233.     printf("+ Saving to %s\r\n", savebox);
  234.       else
  235.     printf("- Can't access file %s\r\n", savebox);
  236.       break;
  237.     }
  238.     break;
  239.   case ITEM:
  240.     if (!opened) {
  241.       printf("- No open mailbox\r\n");
  242.       return (-1);
  243.     }
  244.     switch (token) {
  245.     case raed:
  246.       if (myargc) cur_msg = atoi(myargv[1]);
  247.       if (cur_msg < 1) {
  248.     printf("- Illegal message number\r\n");
  249.     return (-1);
  250.       }
  251.       break;
  252.     case ackd:
  253.       msg[cur_msg].deleted = 1;
  254.     case acks:
  255.       cur_msg++;
  256.     case nack:
  257.       break;
  258.     }
  259.     if (cur_msg_len = msglen(cur_msg))
  260.       printf("=%d characters in message %d\r\n", cur_msg_len, cur_msg);
  261.     else
  262.       printf("=0 no more messages\r\n");
  263.     break;
  264.   case NEXT:
  265.     if (!cur_msg_len) {
  266.       printf("- Zero length message\r\n");
  267.       return (-1);
  268.     }
  269.     outmsg(cur_msg);
  270.     break;
  271.   case DONE:
  272.     printf("+ OK, bye, bye\r\n");
  273.     closeit();
  274.     return 0;
  275.   case ERRO:
  276.     printf("- Syntax error\r\n");
  277.     return (-1);
  278.   }
  279.   cur_state = next_state;
  280.   return 1;
  281. }
  282.  
  283. /*---------------------------------------------------------------------------*/
  284.  
  285. /* Check userid and password */
  286.  
  287. static int  check_user(user, passwd)
  288. char  *user, *passwd;
  289. {
  290.   char  *namep;
  291.  
  292.   pwd = getpwnam(user);
  293.   if (!pwd) return (-1);
  294.   namep = crypt(passwd, pwd->pw_passwd);
  295.   if (strcmp(namep, pwd->pw_passwd)) return (-1);
  296.   setgid(pwd->pw_gid);
  297.   initgroups(user, (int) pwd->pw_gid);
  298.   setuid(pwd->pw_uid);
  299.   chdir(pwd->pw_dir);
  300.   umask(077);
  301.   return 0;
  302. }
  303.  
  304. /*---------------------------------------------------------------------------*/
  305.  
  306. /* Perform lexical analysis on incomming stuff */
  307.  
  308. static int  lexical()
  309. {
  310.  
  311.   char  inline[1024];
  312.   int  i;
  313.  
  314.   for (i = 0; i < 3; i++) myargv[i][0] = '\0';
  315.   myargc = -1;
  316.   while (myargc < 0) {
  317.     if (my_gets(inline) < 0) return (-1);
  318.     myargc = sscanf(inline, "%s%s%s", myargv[0], myargv[1], myargv[2]);
  319.     myargc--;
  320.   }
  321.   key = keytab[whatkey(myargv[0])];
  322.   if (key.val == null) {
  323.     printf("- Invalid command '%s'\r\n", myargv[0]);
  324.     return (-1);
  325.   }
  326.   if (key.args && ((key.args - myargc) > 1)) {
  327.     printf("- Not enough arguments for '%s'\r\n", myargv[0]);
  328.     return (-1);
  329.   }
  330.   return key.val;
  331. }
  332.  
  333. /*---------------------------------------------------------------------------*/
  334.  
  335. /* Now determine which keyword we've got... */
  336.  
  337. static int  whatkey(s)
  338. char  *s;
  339. {
  340.   int  i;
  341.  
  342.   for (i = 0; i < 4; i++) s[i] = tolower(s[i] & 0xff);
  343.   for (i = NKEYS; i > 0; i--)
  344.     if (!strncmp(keytab[i].key, s, 4)) return keytab[i].val;
  345.   return null;
  346. }
  347.  
  348. /*---------------------------------------------------------------------------*/
  349.  
  350. /* Open the specified mailbox */
  351.  
  352. static int  openit()
  353. {
  354.  
  355.   FILE * fmail;
  356.   struct stat statb;
  357.  
  358.   if (opened) closeit();
  359.   nmsg = 0;
  360.   nlines = 0;
  361.   strcpy(mailtmp, tmplate);
  362.   mktemp(mailtmp);
  363.   unlink(mailtmp);
  364.   if (!(ftemp = fopen(mailtmp, "w+"))) return 0;
  365.   if (!(fmail = fopen(mailbox, "r+"))) {
  366.     fclose(ftemp);
  367.     unlink(mailtmp);
  368.     return 0;
  369.   }
  370.   flock(fmail, F_WRLCK);
  371.   if (fstat(fileno(fmail), &statb) || statb.st_size == 0) {
  372.     fclose(ftemp);
  373.     unlink(mailtmp);
  374.     fclose(fmail);
  375.     return 0;
  376.   }
  377.   while (fgets(line, sizeof(line), fmail)) {
  378.     if (strncmp("From ", line, 5) == 0) {
  379.       msg[nmsg++].lines = nlines;
  380.       nlines = 0;
  381.       msg[nmsg].headp = ftell(fmail) - strlen(line);
  382.     } else
  383.       nlines++;
  384.     fputs(line, ftemp);
  385.   }
  386.   msg[nmsg].lines = nlines;
  387.   msg[nmsg+1].headp = ftell(fmail);
  388.   fclose(fmail);
  389.   cur_msg = 1;
  390.   opened = 1;
  391.   return nmsg;
  392. }
  393.  
  394. /*---------------------------------------------------------------------------*/
  395.  
  396. static void closeit()
  397. {
  398.  
  399.   FILE * fmail;
  400.   int  changed;
  401.   int  i;
  402.   int  j;
  403.   struct stat statb;
  404.  
  405.   if (!opened) return;
  406.   changed = 0;
  407.   for (i = 1; i <= nmsg; i++)
  408.     if (msg[i].deleted) {
  409.       changed = 1;
  410.       break;
  411.     }
  412.   if (changed) {
  413.     signal(SIGINT, SIG_IGN);
  414.     signal(SIGHUP, SIG_IGN);
  415.     signal(SIGQUIT, SIG_IGN);
  416.     if (!(fmail = fopen(mailbox, "r+"))) return;
  417.     flock(fmail, F_WRLCK);
  418.     fstat(fileno(fmail), &statb);
  419.     if (statb.st_size != msg[nmsg+1].headp) {
  420.       fseek(fmail, msg[nmsg+1].headp, SEEK_SET);
  421.       fseek(ftemp, msg[nmsg+1].headp, SEEK_SET);
  422.       nlines = 0;
  423.       while (fgets(line, sizeof(line), fmail)) {
  424.     nlines++;
  425.     fputs(line, ftemp);
  426.       }
  427.       nmsg++;
  428.       msg[nmsg].lines = nlines - 1;
  429.       msg[nmsg+1].headp = ftell(ftemp);
  430.     }
  431. #if 0
  432.     ftruncate(fileno(fmail), 0L);
  433. #else
  434.     close(creat(mailbox, 0660));
  435. #endif
  436.     rewind(fmail);
  437.     for (i = 1; i <= nmsg; i++) {
  438.       if (!msg[i].deleted || fsave) {
  439.     fseek(ftemp, msg[i].headp, SEEK_SET);
  440.     for (j = 0; j <= msg[i].lines; j++) {
  441.       fgets(line, sizeof(line), ftemp);
  442.       fputs(line, msg[i].deleted ? fsave : fmail);
  443.     }
  444.       }
  445.     }
  446.     fclose(fmail);
  447.   }
  448.   fclose(ftemp);
  449.   unlink(mailtmp);
  450.   opened = 0;
  451. }
  452.  
  453. /*---------------------------------------------------------------------------*/
  454.  
  455. /* Compute a message's length. <lf> counts as <cr><lf> */
  456.  
  457. static int  msglen(n)
  458. {
  459.   struct message *m;
  460.  
  461.   if (n > nmsg || msg[n].deleted) return 0;
  462.   m = msg + n;
  463.   fseek(ftemp, m->headp, SEEK_SET);
  464.   fgets(line, sizeof(line), ftemp);
  465.   return (msg[n+1].headp - m->headp) - strlen(line) + m->lines;
  466. }
  467.  
  468. /*---------------------------------------------------------------------------*/
  469.  
  470. /*
  471.  * Output msg to primary, convert to net standard ascii.
  472.  * We are already positioned at the first line.
  473.  */
  474.  
  475. static void outmsg(n)
  476. int  n;
  477. {
  478.   int  i;
  479.  
  480.   for (i = msg[n].lines; i > 0; i--) {
  481.     fgets(line, sizeof(line), ftemp);
  482.     line[strlen(line)-1] = '\0';
  483.     printf("%s\r\n", line);
  484.   }
  485. }
  486.  
  487. /*---------------------------------------------------------------------------*/
  488.  
  489. /* Read an entire line from the network */
  490.  
  491. static int  my_gets(s)
  492. char  *s;
  493. {
  494.   int  c;
  495.  
  496.   fflush(stdout);
  497.   while ((c = getchar()) != '\n') {
  498.     if (ferror(stdin) || feof(stdin)) return (-1);
  499.     if (c != '\r') *s++ = c;
  500.   }
  501.   *s = '\0';
  502.   return 0;
  503. }
  504.  
  505. /*---------------------------------------------------------------------------*/
  506.  
  507. /* Open a backup file for deleted messages */
  508.  
  509. static int  openbk(savefile)
  510. char  *savefile;
  511. {
  512.   if (fsave) fclose(fsave);
  513.   if (fsave = fopen(savefile, "a")) return 1;
  514.   return 0;
  515. }
  516.  
  517. /*---------------------------------------------------------------------------*/
  518.  
  519. static int  flock(fp, l_type)
  520. FILE *fp;
  521. int  l_type;
  522. {
  523.   struct flock flk;
  524.  
  525.   flk.l_whence = 0;
  526.   flk.l_len = 0;
  527.   flk.l_type = l_type;
  528.   return fcntl(fileno(fp), F_SETLKW, &flk);
  529. }
  530.  
  531.